﻿//==================================================
// Copyright (C) 2016-2017 Fanjia
// All rights reserved
// CLR 版本: 4.0.30319.42000
// 机器名称: ZHX
// 文 件 名: GeoHelper
// 创建时间: 2017/9/29 9:44:09
// 创 建 人: 张华鑫
//==================================================

using System;
using GeoCoordinate = WindowsFormsApplication1.Common.GeoCoordinate;

namespace WindowsFormsApplication1.Common
{
    /// <summary>
    /// 地理帮助类
    /// </summary>
    public static class GeoHelper
    {
        private const double XPI = Math.PI * 3000 / 180;

        /// <summary>
        /// 将百度坐标系（BD-09）转换成火星坐标系（GCJ-02）
        /// </summary>
        /// <param name="longitude">百度坐标系的经度</param>
        /// <param name="latitude">百度坐标系的纬度</param>
        /// <returns>火星坐标系的经纬度</returns>
        public static Tuple<double?, double?> TransformBD09ToGCJ02(double longitude, double latitude)
        {
            if (longitude < 72.004 || longitude > 137.8347 || latitude < 0.8293 || latitude > 55.8271)
            {
                return new Tuple<double?, double?>(null, null);
            }
            var x = longitude - 0.0065;
            var y = latitude - 0.006;
            var z = Math.Sqrt(x * x + y * y) - 0.00002 * Math.Sin(y * XPI);
            var theta = Math.Atan2(y, x) - 0.000003 * Math.Cos(x * XPI);
            return new Tuple<double?, double?>(z * Math.Cos(theta), z * Math.Sin(theta));
        }

        /// <summary>
        /// 获取地理距离
        /// </summary>
        /// <param name="longitudeSource">经度（来源）</param>
        /// <param name="latitudeSource">纬度（来源）</param>
        /// <param name="longitudeTarget">经度（目标）</param>
        /// <param name="latitudeTarget">纬度（目标）</param>
        /// <returns>地理距离</returns>
        public static double? GetGeoDistance(double? longitudeSource, double? latitudeSource, double? longitudeTarget,
            double? latitudeTarget)
        {
            if (longitudeSource == null || latitudeSource == null || longitudeTarget == null || latitudeTarget == null)
            {
                return null;
            }
            if (Math.Abs(longitudeSource.Value) > 180 || Math.Abs(latitudeSource.Value) > 90 ||
                Math.Abs(longitudeTarget.Value) > 180 || Math.Abs(latitudeTarget.Value) > 90)
            {
                return null;
            }
            return new GeoCoordinate(latitudeSource.Value, longitudeSource.Value).GetDistanceTo(
                new GeoCoordinate(latitudeTarget.Value, longitudeTarget.Value));
        }

        /// <summary>
        /// 获取坐标相似度
        /// </summary>
        /// <param name="longitudeSource">经度（来源）</param>
        /// <param name="latitudeSource">纬度（来源）</param>
        /// <param name="longitudeTarget">经度（目标）</param>
        /// <param name="latitudeTarget">纬度（目标）</param>
        /// <returns>坐标相似度</returns>
        public static double GetCoordinateSimilarity(double? longitudeSource, double? latitudeSource,
            double? longitudeTarget, double? latitudeTarget)
        {
            var geoDistance = GetGeoDistance(longitudeSource, latitudeSource, longitudeTarget, latitudeTarget);
            return geoDistance != null
                ? geoDistance <= 100 ? 1 : (geoDistance > 1000 ? 0 : Math.Floor((1100 - geoDistance.Value) / 100) / 10)
                : 0;
        }
    }
}
